// annotation 注解@，简单地对于对象、类、方法、属性等进行描述加工

// 如果我想在类声明的时候额外做一些事：类的装饰器
// 属性获取和设置的时候额外做一些事：属性的装饰器
// 方法调用的时候额外做一些事：方法的装饰器

// 装饰器：本质就是一个函数
function LogClass(constructor: Function) {
    console.log("类装饰器: ", constructor);
}

function LogProperty(message: string) {
    console.log('🚀 ~ 属性装饰器 ~ message:', message)
    return function (target: any, key: string) {
        console.log("~ 属性装饰器:", target, key)
    };
}

function LogMethod() {
    return function (target: any, key: string, descriptor: PropertyDescriptor) {
        console.log("~方法装饰器 target:", target, key, descriptor)
    };
}

function GetMethod() {
    return function (target: any, key: string, descriptor: PropertyDescriptor) {
        console.log("~ 访问器装饰器:", target, key, descriptor)

        // 保存原始方法
        const originalMethod = descriptor.value;

        // 重写方法实现
        descriptor.value = function (...args: any[]) {
            // 执行原始方法
            const result = originalMethod.apply(this, args);

            // 返回原始结果
            return result;
        };
        return descriptor;
    };
}

// 全部都是面向切面编程的思想
@LogClass // 类的装饰器
export class AnnotationPerson {
    @LogProperty("我是一条message") // 属性的装饰器
    cname: string = "orange";

    constructor(name: string) {
        this.cname = name;
    }

    @LogMethod() // 方法的装饰器
    sayHello() {
        console.log("你好");
    }

    @GetMethod() // 方法的装饰器
    getName() {
        return this.cname;
    }
}

const oPerson = new AnnotationPerson("orange");
oPerson.sayHello();
console.log(oPerson.getName());